package org.redmagic.agent;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.redmagic.exception.UnresolvablePlaceholderException;
import org.redmagic.location.Location;
import org.redmagic.location.LocationFactory;
import org.redmagic.utils.Conditions;

/**
 * @deprecated Should switch to using {@link ChainedLocation} instead.
 */
@Deprecated
public class PropertyLocator implements Location {

	private static final Log LOG = LogFactory.getLog(PropertyLocator.class);
	
	private final List<Location> locations;
	private final boolean ignoreUnresolvableProperties;
	private final Object lock;
	
	public PropertyLocator(LocationFactory locationFactory) {
		this(locationFactory, false);
	}
	
	public PropertyLocator(LocationFactory locationFactory, boolean ignoreUnresolvableProperties) {
	    Conditions.notNull(locationFactory, "locationFactory");
		this.locations = new ArrayList<Location>(locationFactory.getLocations());
		this.ignoreUnresolvableProperties = ignoreUnresolvableProperties;
		this.lock = new Object();
	}
	
	@Override
	public Properties resolvePlaceholders(Set<String> placeholders) {
		synchronized(lock) {
			
			// as we resolve properties, we remove them from this list.
			Set<String> unresolvedPlaceholders = new HashSet<String>(placeholders);
			
			// check each location, looking for the placeholders
			Properties resolvedPlaceholders = checkLocations(unresolvedPlaceholders);
			
			// check if it's safe to ignore any unresolved placeholders
			validatePlaceholders(unresolvedPlaceholders);
			
			// clean up
			postProcess(resolvedPlaceholders);
			
			return resolvedPlaceholders;
		}
	}

	private Properties checkLocations(Set<String> unresolvedPlaceholders) {
		Properties resolvedProperties = new Properties();
		
		for (Location location : this.locations) {
			boolean finished = checkLocation(location, unresolvedPlaceholders, resolvedProperties);
			if (finished) {
				break;
			}			
		}
		
		return resolvedProperties;
	}
	
	private boolean checkLocation(Location location, Set<String> unresolvedPlaceholders, Properties resolvedProperties) {
		Properties results = location.resolvePlaceholders(unresolvedPlaceholders);
		LOG.info("Resolved " + results.size() + " of " + unresolvedPlaceholders.size() + " remaining placeholders from location: " + location);
		resolvedProperties.putAll(results);
		
		// remove placeholders we've found
		for (Object placeholder : results.keySet()) {
			unresolvedPlaceholders.remove(placeholder);
		}
		
		// end if there are no more placeholders to find
		return unresolvedPlaceholders.isEmpty();
	}
	
	private void validatePlaceholders(Set<String> unresolvedPlaceholders) {
		if (!ignoreUnresolvableProperties && !unresolvedPlaceholders.isEmpty()) {
			for (String unresolvedPlaceholder : unresolvedPlaceholders) {
				LOG.error("Unable to resolve placeholder: " + unresolvedPlaceholder);
			}
			
			throw new UnresolvablePlaceholderException("Unable to resolve "
			                            + unresolvedPlaceholders.size()
			                            + " placeholders", unresolvedPlaceholders);
		}
	}

	@Override
	public void postProcess(Properties properties) {
		for (Location location : this.locations) {
			location.postProcess(properties);
		}
	}
}